package web

import (
	"context"
	"errors"
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"github.com/redis/go-redis/v9"
	"go.uber.org/zap"
	"io"
	"mts/user_srv/form"
	"mts/user_srv/internal/domain"
	"mts/user_srv/internal/models"
	"mts/user_srv/internal/service"
	"mts/user_srv/internal/web/middleware"
	"mts/user_srv/internal/web/response"
	"net/http"
	"strconv"
	"time"
)

type ActionType string
type LogType string

const (
	ActionLogin     ActionType = "用户登录"
	ActionDelete    ActionType = "删除用户"
	ActionUpdate    ActionType = "更新用户"
	ActionAdd       ActionType = "创建用户"
	ActionUpdatePwd ActionType = "更新密码"
	TypeCreate      LogType    = "create"
	TypeUpdate      LogType    = "update"
	TypeDelete      LogType    = "delete"
	TypeLogin       LogType    = "login"
)

// UserHandler 依赖 UserService 接口
type UserHandler struct {
	svc     service.UserService
	codeSvc service.CodeService
}

// NewUserHandler 依赖注入 UserService 接口
func NewUserHandler(svc service.UserService, codeSvc service.CodeService) *UserHandler {
	return &UserHandler{
		svc:     svc,
		codeSvc: codeSvc,
	}
}

func (handler *UserHandler) RegisterRoutes(group *gin.RouterGroup) {
	zap.S().Info("配置用户相关url")
	//路由分组
	ug := group.Group("/user")
	ug.POST("login", handler.PassWordLogin)
	ug.POST("register", handler.Register)
	ug.GET("current", middlewares.JWTAuth(), handler.GetCurrentUser)
	ug.POST("add", middlewares.JWTAuth(), middlewares.IsAdminAuth(), handler.AddUser)
	ug.GET("list", middlewares.JWTAuth(), middlewares.IsAdminAuth(), handler.GetUserList)
	ug.DELETE("delete/:id", middlewares.JWTAuth(), middlewares.IsAdminAuth(), handler.DeleteUser)
	ug.PUT("update/:id", middlewares.JWTAuth(), handler.UpdateByUserId)
	ug.GET("/count", handler.Count)
	ug.POST("login/other", handler.PassWordLoginWithBlog)
	ug.POST("updatePwd/:id", middlewares.JWTAuth(), handler.UpdatePassword)
	ug.POST("update/u/:id", middlewares.JWTAuth(), handler.UpdatePersonInfo)
}

// DeleteUser 删除用户
func (handler *UserHandler) DeleteUser(ctx *gin.Context) {
	id := ctx.Param("id")
	userId, err := strconv.ParseInt(id, 10, 32)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"msg": "无效的用户参数"})
		return
	}
	if _, err := handler.svc.DeleteUser(ctx, &domain.IdRequest{ID: int32(userId)}); err != nil {
		zap.S().Errorw("删除用户失败", "err", err)
		ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
		return
	}
	//发送消息到rabbitmq服务
	handler.SendMessage(ctx, ActionDelete, TypeDelete, fmt.Sprintf("删除了%d 的信息", userId))
	ctx.JSON(http.StatusOK, gin.H{
		"msg": "删除成功",
	})
}

// UpdateByUserId 更新用户信息
func (handler *UserHandler) UpdateByUserId(ctx *gin.Context) {
	id := ctx.Param("id")
	userId, err := strconv.ParseUint(id, 10, 64)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"msg": "无效的用户参数"})
		return
	}
	claims, _ := ctx.Get("claims")
	currentUser := claims.(*models.CustomClaims)
	var updateForm domain.UserUpdateForm

	if err := ctx.ShouldBind(&updateForm); err != nil {
		if errors.Is(err, io.EOF) {
			ctx.JSON(http.StatusBadRequest, gin.H{"msg": "请求体为空"})
			return
		}
		zap.S().Errorw("表单绑定失败", "err", err)
		response.HandlerValidatorError(ctx, err)
		return
	}

	// 设置更新表单的 ID
	updateForm.ID = int32(userId)

	// 验证 BirthDay 字段（假设是时间戳）
	nanoseconds := updateForm.BirthDay * int64(time.Millisecond)
	birthTime := time.Unix(0, nanoseconds)
	year := birthTime.Year()
	if year < 1 || year > 9999 {
		ctx.JSON(http.StatusBadRequest, gin.H{"msg": "无效的出生年份"})
		return
	}

	// 权限控制逻辑开始
	var targetUser *domain.UserInfoResponse
	targetUser, err = handler.svc.GetUserById(ctx, &domain.IdRequest{ID: updateForm.ID})
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"msg": "获取目标用户信息失败"})
		return
	}

	isAdmin := currentUser.AuthorityId == 2
	isSelf := int32(currentUser.Id) == updateForm.ID
	isTargetAdmin := targetUser.Role == 2

	if !isAdmin && !isSelf {
		// 普通用户只能修改自己
		ctx.JSON(http.StatusForbidden, gin.H{"msg": "没有权限更新该用户信息"})
		return
	}

	if isAdmin && isTargetAdmin && !isSelf {
		// 管理员不能修改其他管理员的信息
		ctx.JSON(http.StatusForbidden, gin.H{"msg": "管理员不能修改其他管理员的信息"})
		return
	}

	if isAdmin && isSelf && updateForm.Role != 2 {
		// 管理员不能将自己降权
		ctx.JSON(http.StatusForbidden, gin.H{"msg": "管理员不能将自己的角色修改为普通用户"})
		return
	}

	// 允许管理员更新普通用户信息（可包含升权）

	if _, err := handler.svc.UpdateUser(ctx, &updateForm, int32(currentUser.AuthorityId)); err != nil {
		zap.S().Errorw("[UpdateUser] 更新 【用户信息】 失败", "err", err)
		ctx.JSON(http.StatusInternalServerError, gin.H{"code": 400, "msg": "更新用户失败: " + err.Error()})
		return
	}

	var actionInfo string
	if uint64(currentUser.Id) == userId {
		actionInfo = "自己的"
	} else {
		actionInfo = strconv.Itoa(int(userId))
	}
	handler.SendMessage(ctx, ActionUpdate, TypeUpdate, fmt.Sprintf("更新了%s的信息", actionInfo))

	ctx.JSON(http.StatusOK, gin.H{
		"code": 200,
		"msg":  "更新成功",
	})
}

// GetUserList 处理 API 请求
func (handler *UserHandler) GetUserList(ctx *gin.Context) {
	claims, _ := ctx.Get("claims")
	currentUser := claims.(*models.CustomClaims)
	zap.S().Infof("访问用户: %d", currentUser.Id)

	pn := ctx.DefaultQuery("pn", "0")
	pnInt, _ := strconv.Atoi(pn)
	pSize := ctx.DefaultQuery("psize", "10")
	pSizeInt, _ := strconv.Atoi(pSize)
	resp, err := handler.svc.GetUserList(context.Background(), &domain.PageInfo{
		Pn:    uint32(pnInt),
		PSize: uint32(pSizeInt),
	})
	if err != nil {
		zap.S().Errorw("[GetUserList] 查询 【用户列表】 失败")
		ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
		return
	}

	result := make([]interface{}, 0)
	for _, val := range resp.Data {
		unix := time.Unix(int64(val.BirthDay), 0)
		user := response.UserResponse{
			Id:        val.ID,
			NickName:  val.NickName,
			BirthDay:  response.JsonTime(unix),
			Gender:    val.Gender,
			Mobile:    val.Mobile,
			Role:      val.Role,
			IsDeleted: val.IsDeleted,
		}
		result = append(result, user)
	}
	count, _ := handler.svc.Count(ctx)
	ctx.JSON(http.StatusOK, gin.H{
		"code": 200, "data": result, "total": count,
	})
	zap.S().Debug("获取用户列表页")
}

func (handler *UserHandler) UpdatePersonInfo(ctx *gin.Context) {
	//验证用户是否存在
	idStr := ctx.Param("id")
	if idStr == "" {
		ctx.JSON(http.StatusBadRequest, gin.H{"msg": "用户id不能为空"})
		return
	}

	var updateForm domain.UserUpdateForm
	id, err := strconv.Atoi(idStr)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"msg": "系统异常"})
		return
	}
	updateForm.ID = int32(id)
	if err := ctx.ShouldBind(&updateForm); err != nil {
		if errors.Is(err, io.EOF) {
			ctx.JSON(http.StatusBadRequest, gin.H{"msg": "请求体为空"})
			return
		}
		zap.S().Errorw("表单绑定失败", "err", err)
		response.HandlerValidatorError(ctx, err)
		return
	}
	if _, err := handler.svc.UpdateUser(ctx, &updateForm, 1); err != nil {
		zap.S().Errorw("[UpdateUser] 更新 【用户信息】 失败", "err", err)
		ctx.JSON(http.StatusInternalServerError, gin.H{"code": 400, "msg": "更新个人信息失败: " + err.Error()})
		return
	}
	handler.SendMessage(ctx, ActionUpdate, TypeUpdate, "更新了个人信息")
	ctx.JSON(http.StatusOK, gin.H{"code": 200, "msg": "更新个人信息成功"})
}

// GetCurrentUser 获取当前用户信息
func (handler *UserHandler) GetCurrentUser(ctx *gin.Context) {
	claims, exists := ctx.Get("claims")
	if !exists {
		ctx.JSON(http.StatusUnauthorized, gin.H{"msg": "未授权"})
		return
	}
	currentUser := claims.(*models.CustomClaims)

	// 获取用户信息
	user, err := handler.svc.GetUserById(ctx, &domain.IdRequest{ID: int32(currentUser.Id)})
	if err != nil {
		zap.S().Errorw("获取当前用户信息失败", "err", err)
		ctx.JSON(http.StatusInternalServerError, gin.H{"msg": "获取用户信息失败: " + err.Error()})
		return
	}
	ctx.JSON(http.StatusOK, user)
}

// PassWordLoginWithBlog 多语言应用web页面登录
func (handler *UserHandler) PassWordLoginWithBlog(ctx *gin.Context) {
	// 1. 表单验证
	var loginForm form.PassWordLoginFormWithBlog
	if err := ctx.ShouldBind(&loginForm); err != nil {
		if errors.Is(err, io.EOF) {
			ctx.JSON(http.StatusBadRequest, gin.H{"msg": "请求体为空"})
			return
		}
		zap.S().Errorw("表单绑定失败", "err", err)
		response.HandlerValidatorError(ctx, err)
		return
	}
	// 3. 获取用户信息
	rsp, err := handler.svc.GetUserByMobile(context.Background(), &domain.MobileRequest{Mobile: loginForm.Mobile})
	if err != nil {
		zap.S().Errorw("[PassWordLogin] 获取用户失败", "err", err)
		ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
		return
	}

	// 4. 检查密码
	passRsp, passErr := handler.svc.CheckPassWord(context.Background(), &domain.CheckPassWordInfo{
		Password:          loginForm.PassWord,
		EncryptedPassword: rsp.PassWord,
	})
	if passErr != nil {
		zap.S().Errorw("[PassWordLogin] 密码验证失败", "err", passErr)
		ctx.JSON(http.StatusInternalServerError, gin.H{"msg": passErr.Error()})
		return
	}
	//5.检查是否被停用
	if rsp.IsDeleted {
		ctx.JSON(http.StatusBadRequest, gin.H{"msg": "用户被停用"})
		return
	}
	if passRsp.Success {
		ResponseUserInfo(ctx, rsp, err)
		handler.SendMessage(ctx, ActionLogin, TypeLogin, fmt.Sprintf("用户%s登录系统", rsp.NickName))
		return
	} else {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "密码错误"})
	}
}

// PassWordLogin 密码登录
func (handler *UserHandler) PassWordLogin(ctx *gin.Context) {
	// 1. 表单验证
	var loginForm form.PassWordLoginForm
	if err := ctx.ShouldBind(&loginForm); err != nil {
		if errors.Is(err, io.EOF) {
			ctx.JSON(http.StatusBadRequest, gin.H{"msg": "请求体为空"})
			return
		}
		zap.S().Errorw("表单绑定失败", "err", err)
		response.HandlerValidatorError(ctx, err)
		return
	}
	//校验图形验证码
	if !store.Verify(loginForm.CaptchaId, loginForm.Captcha, true) {
		ctx.JSON(http.StatusBadRequest, gin.H{
			"captcha": "验证码错误",
		})
		return
	}
	// 3. 获取用户信息
	rsp, err := handler.svc.GetUserByMobile(context.Background(), &domain.MobileRequest{Mobile: loginForm.Mobile})
	if err != nil {
		zap.S().Errorw("[PassWordLogin] 获取用户失败", "err", err)
		ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
		return
	}
	// 4. 检查密码
	passRsp, passErr := handler.svc.CheckPassWord(context.Background(), &domain.CheckPassWordInfo{
		Password:          loginForm.PassWord,
		EncryptedPassword: rsp.PassWord,
	})
	if passErr != nil {
		zap.S().Errorw("[PassWordLogin] 密码验证失败", "err", passErr)
		ctx.JSON(http.StatusInternalServerError, gin.H{"msg": passErr.Error()})
		return
	}
	//5.检查是否被停用
	if rsp.IsDeleted {
		ctx.JSON(http.StatusBadRequest, gin.H{"msg": "用户被停用"})
		return
	}
	if passRsp.Success {
		ResponseUserInfo(ctx, rsp, err)
		handler.SendMessage(ctx, ActionLogin, TypeLogin, fmt.Sprintf("用户%s登录系统", rsp.NickName))
		return
	} else {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "密码错误"})
	}
}
func (handler *UserHandler) AddUser(ctx *gin.Context) {
	registerForm := form.AddUserForm{}
	//表单验证
	if err := ctx.ShouldBind(&registerForm); err != nil {
		if errors.Is(err, io.EOF) {
			ctx.JSON(http.StatusBadRequest, gin.H{"msg": "请求体为空"})
			return
		}
		zap.S().Errorw("表单绑定失败", "err", err)
		response.HandlerValidatorError(ctx, err)
		return
	}
	user, err := handler.svc.CreateUser(context.Background(), &domain.CreateUserInfo{
		NickName: registerForm.Mobile,
		Mobile:   registerForm.Mobile,
		PassWord: registerForm.PassWord,
	})
	if err != nil {
		zap.S().Errorf("添加 【用户失败】:%s", err.Error())
		ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
		return
	}
	//发送消息到rabbitmq服务
	handler.SendMessage(ctx, ActionAdd, TypeCreate, fmt.Sprintf("创建了%s用户", user.NickName))
	ctx.JSON(http.StatusOK, gin.H{
		"msg": "创建用户成功",
	})
}
func (handler *UserHandler) Register(ctx *gin.Context) {
	registerForm := form.RegisterForm{}
	//表单验证
	if err := ctx.ShouldBind(&registerForm); err != nil {
		if errors.Is(err, io.EOF) {
			ctx.JSON(http.StatusBadRequest, gin.H{"msg": "请求体为空"})
			return
		}
		zap.S().Errorw("表单绑定失败", "err", err)
		response.HandlerValidatorError(ctx, err)
		return
	}
	// 1.验证码校验
	val, err := handler.codeSvc.GetCode(registerForm.Mobile)
	if errors.Is(err, redis.Nil) || registerForm.Code != val {
		ctx.JSON(http.StatusBadRequest, gin.H{
			"code": "验证码错误",
		})
		return
	}
	// 2.创建用户
	user, err := handler.svc.CreateUser(context.Background(), &domain.CreateUserInfo{
		NickName: registerForm.Mobile,
		Mobile:   registerForm.Mobile,
		PassWord: registerForm.PassWord,
	})
	if err != nil {
		zap.S().Errorf("[Register] 查询 【新建用户失败】:%s", err.Error())
		ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
		return
	}
	zap.S().Infof("创建用户:%v", user)
	ResponseUserInfo(ctx, user, err)
}

func (handler *UserHandler) Count(ctx *gin.Context) {
	count, err := handler.svc.Count(ctx)
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"code": 400,
			"msg":  "系统异常",
		})
		return
	}
	ctx.JSON(http.StatusOK, gin.H{
		"users": count,
	})
}

// UpdatePassword 更新用户密码
//func (handler *UserHandler) UpdatePassword(ctx *gin.Context) {
//	id := ctx.Param("id")
//	var updatePasswordForm form.UpdatePasswordForm
//	if err := ctx.ShouldBind(&updatePasswordForm); err != nil {
//		if errors.Is(err, io.EOF) {
//			ctx.JSON(http.StatusBadRequest, gin.H{"msg": "请求体为空"})
//			return
//		}
//		zap.S().Errorw("表单绑定失败", "err", err)
//		response.HandlerValidatorError(ctx, err)
//		return
//	}
//	// 调用服务层方法更新密码
//	if err := handler.svc.UpdatePassword(ctx, &form.UpdatePasswordForm{
//		OldPass: updatePasswordForm.OldPassword,
//		NewPass: updatePasswordForm.NewPassword,
//	}); err != nil {
//		zap.S().Errorw("[UpdatePassword] 更新 【用户密码】 失败", "err", err)
//		ctx.JSON(http.StatusInternalServerError, gin.H{"msg": "更新密码失败: " + err.Error()})
//		return
//	}
//	handler.SendMessage(ctx, ActionUpdatePwd, TypeUpdate, fmt.Sprintf("更新了用户%d的密码", id))
//	ctx.JSON(http.StatusOK, gin.H{
//		"msg": "密码更新成功",
//	})
//}

func ResponseUserInfo(ctx *gin.Context, user *domain.UserInfoResponse, err error) {
	//生成token
	j := middlewares.NewJWT()
	//签名
	claims := models.CustomClaims{
		Id:          uint(user.ID),
		NickName:    user.NickName,
		AuthorityId: uint(user.Role),
		StandardClaims: jwt.StandardClaims{
			NotBefore: time.Now().Unix(),               //签名生效时间
			ExpiresAt: time.Now().Unix() + 60*60*24*30, //过期时间
			Issuer:    "seina",                         //认证机构
		},
	}

	token, err := j.CreateToken(claims)
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"msg": "生成token失败"})
		return
	}
	//登录成功 返回信息
	ctx.JSON(http.StatusOK, gin.H{
		"id":         user.ID,
		"nick_name":  user.NickName,
		"token":      token,
		"role":       user.Role,
		"expired_at": (time.Now().Unix() + 60*60*24*30) * 1000,
	})
}

func (handler *UserHandler) getCurrentUser(ctx *gin.Context) *models.CustomClaims {
	claims, _ := ctx.Get("claims")
	return claims.(*models.CustomClaims)
}

func (handler *UserHandler) SendMessage(ctx *gin.Context, a ActionType, t LogType, d string) {
	currentUser := handler.getCurrentUser(ctx)
	//发送消息到rabbitmq服务
	err := handler.svc.Publish(map[string]interface{}{
		"user_id":   currentUser.NickName,
		"action":    a,
		"type":      t,
		"details":   d,
		"timestamp": time.Now(),
	})
	if err != nil {
		zap.S().Errorf("记录日志失败:%s", err)
	}
}

func (handler *UserHandler) UpdatePassword(ctx *gin.Context) {
	idStr := ctx.Param("id")
	if idStr == "" {
		ctx.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "id不能为空"})
		return
	}
	updatePasswordForm := form.UpdatePasswordForm{}
	if err := ctx.ShouldBind(&updatePasswordForm); err != nil {
		if errors.Is(err, io.EOF) {
			ctx.JSON(http.StatusBadRequest, gin.H{"msg": "请求参数为空"})
			return
		}
		zap.S().Errorw("表单绑定失败", "err", err)
		response.HandlerValidatorError(ctx, err)
		return
	}
	if updatePasswordForm.NewPassword == updatePasswordForm.OldPassword {
		ctx.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "新密码不能与旧密码相同"})
		return
	}
	id, err := strconv.Atoi(idStr)
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"msg": "系统错误"})
		return
	}
	if err := handler.svc.UpdatePassword(ctx, int32(id), &updatePasswordForm); err != nil {
		zap.S().Errorw("[UpdatePassword] 更新 【用户密码】 失败", "err", err)
		ctx.JSON(http.StatusInternalServerError, gin.H{"msg": "更新密码失败: " + err.Error()})
		return
	}
	handler.SendMessage(ctx, ActionUpdatePwd, TypeUpdate, fmt.Sprintf("更新了用户%s的密码", idStr))
	ctx.JSON(http.StatusOK, gin.H{
		"code": 200,
		"msg":  "密码更新成功",
	})
}
